import ChapterSelector from "@/components/manga/chapters";
import Footer from "@/components/shared/footer";
import Head from "next/head";
import { useEffect, useState } from "react";
import { getServerSession } from "next-auth";
import { authOptions } from "../../api/auth/[...nextauth]";
import { mediaInfoQuery } from "@/lib/graphql/query";
import Modal from "@/components/modal";
import { signIn, useSession } from "next-auth/react";
import AniList from "@/components/media/aniList";
import ListEditor from "@/components/listEditor";
import MobileNav from "@/components/shared/MobileNav";
import Image from "next/image";
import DetailTop from "@/components/anime/mobile/topSection";
import Characters from "@/components/anime/charactersCard";
import Content from "@/components/home/content";
import { toast } from "sonner";
import axios from "axios";
import getAnifyInfo from "@/lib/anify/info";
import { redis } from "@/lib/redis";
import getMangaId from "@/lib/anify/getMangaId";
export default function Manga({ info, anifyData, color, chapterNotFound }) {
const [domainUrl, setDomainUrl] = useState("");
const { data: session } = useSession();
const [loading, setLoading] = useState(false);
const [progress, setProgress] = useState(0);
const [statuses, setStatuses] = useState(null);
const [watch, setWatch] = useState();
const [chapter, setChapter] = useState(null);
const [open, setOpen] = useState(false);
const rec = info?.recommendations?.nodes?.map(
(data) => data.mediaRecommendation
);
useEffect(() => {
setDomainUrl(window.location.origin);
}, []);
useEffect(() => {
if (chapterNotFound) {
toast.error("Chapter not found");
const cleanUrl = window.location.origin + window.location.pathname;
window.history.replaceState(null, null, cleanUrl);
}
}, [chapterNotFound]);
useEffect(() => {
async function fetchData() {
try {
setLoading(true);
const { data } = await axios.get(`/api/v2/info?id=${anifyData.id}`);
if (!data.chapters) {
setLoading(false);
return;
}
setChapter(data);
setLoading(false);
} catch (error) {
console.error(error);
}
}
fetchData();
return () => {
setChapter(null);
};
}, [info?.id]);
function handleOpen() {
setOpen(true);
document.body.style.overflow = "hidden";
}
function handleClose() {
setOpen(false);
document.body.style.overflow = "auto";
}
return (
<>
{info
? `Manga - ${
info.title.romaji || info.title.english || info.title.native
}`
: "Getting Info..."}
handleClose()}>
{!session && (
Edit your list
)}
{session && info && (
)}
{/* */}
{info?.bannerImage && (
)}
{!loading ? (
chapter?.chapters?.length > 0 ? (
) : (
Oops!
It looks like this manga is not available.
)
) : (
)}
{info?.characters?.edges?.length > 0 && (
)}
{info && rec && rec?.length !== 0 && (
)}
>
);
}
export async function getServerSideProps(context) {
const session = await getServerSession(context.req, context.res, authOptions);
const accessToken = session?.user?.token || null;
const { chapter } = context.query;
const [id1, id2] = context.query.id;
let cached;
let aniId, mangadexId;
let info, data, color, chapterNotFound;
if (String(id1).length > 6) {
aniId = id2;
mangadexId = id1;
} else {
aniId = id1;
mangadexId = id2;
}
if (chapter) {
// create random id string
chapterNotFound = Math.random().toString(36).substring(7);
}
if (aniId === "na" && mangadexId) {
const datas = await getAnifyInfo(mangadexId);
aniId =
datas.mappings?.filter((i) => i.providerId === "anilist")[0]?.id || null;
if (!aniId) {
info = datas;
data = datas;
color = {
backgroundColor: `${"#ffff"}`,
color: "#000",
};
// return {
// redirect: {
// destination: "/404",
// permanent: false,
// },
// };
}
} else if (aniId && !mangadexId) {
// console.log({ aniId });
const response = await fetch("https://graphql.anilist.co/", {
method: "POST",
headers: {
"Content-Type": "application/json",
...(accessToken && { Authorization: `Bearer ${accessToken}` }),
},
body: JSON.stringify({
query: `query ($id: Int, $type: MediaType) {
Media (id: $id, type: $type) {
id
title {
romaji
english
native
}
}
}`,
variables: {
id: parseInt(aniId),
type: "MANGA",
},
}),
});
const aniListData = await response.json();
const info = aniListData?.data?.Media;
const mangaId = await getMangaId(
info?.title?.romaji,
info?.title?.english,
info?.title?.native
);
mangadexId = mangaId?.id;
if (!mangadexId) {
return {
redirect: {
destination: "/404",
permanent: false,
},
};
}
return {
redirect: {
destination: `/en/manga/${aniId}/${mangadexId}${
chapter ? "?chapter=404" : ""
}`,
permanent: true,
},
};
} else if (!aniId && mangadexId) {
const data = await getAnifyInfo(mangadexId);
aniId =
data.mappings.filter((i) => i.providerId === "anilist")[0]?.id || null;
if (!aniId) {
info = data;
// return {
// redirect: {
// destination: "/404",
// permanent: false,
// },
// };
}
return {
redirect: {
destination: `/en/manga/${aniId ? aniId : "na"}${`/${mangadexId}`}${
chapter ? "?chapter=404" : ""
}`,
permanent: true,
},
};
} else {
if (redis) {
const getCached = await redis.get(`mangaPage:${mangadexId}`);
if (getCached) {
cached = JSON.parse(getCached);
}
}
// let chapters;
if (cached) {
data = cached.data;
info = cached.info;
color = cached.color;
} else {
data = await getAnifyInfo(mangadexId);
const aniListId =
data.mappings?.filter((i) => i.providerId === "anilist")[0]?.id || null;
const response = await fetch("https://graphql.anilist.co/", {
method: "POST",
headers: {
"Content-Type": "application/json",
...(accessToken && { Authorization: `Bearer ${accessToken}` }),
},
body: JSON.stringify({
query: mediaInfoQuery,
variables: {
id: parseInt(aniListId),
type: "MANGA",
},
}),
});
const aniListData = await response.json();
if (aniListData?.data?.Media) info = aniListData?.data?.Media;
const textColor = setTxtColor(info?.color);
color = {
backgroundColor: `${info?.color || "#ffff"}`,
color: textColor,
};
if (redis) {
await redis.set(
`mangaPage:${mangadexId}`,
JSON.stringify({ data, info, color }),
"ex",
60 * 60 * 24
);
}
}
}
return {
props: {
info: info || null,
anifyData: data || null,
chapterNotFound: chapterNotFound || null,
color: color || null,
},
};
}
function getBrightness(hexColor) {
if (!hexColor) {
return 200;
}
const rgb = hexColor
.match(/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i)
.slice(1)
.map((x) => parseInt(x, 16));
return (299 * rgb[0] + 587 * rgb[1] + 114 * rgb[2]) / 1000;
}
function setTxtColor(hexColor) {
const brightness = getBrightness(hexColor);
return brightness < 150 ? "#fff" : "#000";
}